package com.onpositive.wiki3.db.impl;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import com.carrotsearch.hppc.IntOpenHashSet;
import com.onpositive.wiki2.whole.model.ByteStringTable;
import com.onpositive.wiki3.db.ICategoryAccess;
import com.onpositive.wiki3.db.ITitleMapper;
import com.onpositive.wiki3.db.IWikiDB;
import com.onpositive.wiki3.db.catmodel.Categories;
import com.onpositive.wiki3.db.impl.CategoryRefMap.CatInf;

public class CategoryAccessImpl implements ICategoryAccess {

	protected IWikiDB db;
	protected int[] content;
	public int[] getContent() {
		return content;
	}

	protected IntOpenHashSet is = new IntOpenHashSet();
	private File fl;

	public CategoryAccessImpl(File fl, IWikiDB wikiDBImpl) throws IOException {
		this.db = wikiDBImpl;
		this.fl = fl;
		int l = (int) (fl.length() / 4);
		content = new int[l];
		DataInputStream ds = new DataInputStream(new BufferedInputStream(
				new FileInputStream(fl)));
		for (int a = 0; a < l; a++) {
			int readInt = ds.readInt();
			content[a] = readInt;
			if (readInt < 0) {
				is.add(-readInt);
			}
		}
		//
		// test();
	}

	public HashMap<Integer, IntOpenHashSet> parents(IntOpenHashSet ms) {
		HashMap<Integer, IntOpenHashSet> rs = new HashMap<Integer, IntOpenHashSet>(
				10000);
		int cc = -2;
		for (int a = 0; a < content.length; a++) {
			int i = content[a];
			if (i < 0) {
				cc = -i;
			} else {
				if (cc > 0) {
					if (ms.contains(i)) {
						IntOpenHashSet intOpenHashSet = rs.get(i);
						if (intOpenHashSet == null) {
							intOpenHashSet = new IntOpenHashSet();
							rs.put(i, intOpenHashSet);
						}
						intOpenHashSet.add(cc);
					}
				}
			}
		}
		return rs;
	}

	protected void fixCats() {
		ITitleMapper titleMapper = db.getTitleMapper();
		ByteStringTable bs = new ByteStringTable(2000 * 1000);
		for (int a = 0; a < content.length; a++) {

			int c = content[a];
			if (c < 0) {
				int catId = -c;
				String catTitle = titleMapper.getTitle(catId);
				is.add(catId);
				String transform = transform(catTitle);
				if (bs.id2(transform) >= 0) {
					continue;
				}
				bs.put(transform, catId);

				int id = bs.id2(transform);
				// if (id != catId) {
				// System.out.println("Error");
				// }
			}
		}
		for (int a = 0; a < content.length; a++) {

			int c = content[a];
			if (c > 0) {
				int catId = c;
				String catTitle = titleMapper.getTitle(catId);
				int indexOf = catTitle.indexOf("\\n");
				if (indexOf != -1) {
					catTitle = catTitle.substring(indexOf + 2);
				}
				String transform = transform(catTitle);
				int id2 = bs.id2(transform);
				if (id2 <= 0) {
					// if (!db.getContentAccessor().hasText(catId)) {
					// if (!catTitle.startsWith("Portal:")
					// && !catTitle.startsWith("File:")
					// && !catTitle.startsWith("Talk:")) {
					//
					// }
					// }
				} else {
					if (!db.getContentAccessor().hasText(catId)) {
						content[a] = id2;
					}
				}
			}
		}
		try {
			DataOutputStream ds = new DataOutputStream(
					new BufferedOutputStream(new FileOutputStream(fl)));
			for (int a = 0; a < content.length; a++) {
				ds.writeInt(content[a]);
			}
			ds.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private String transform(String catTitle) {
		StringBuilder bld = new StringBuilder();
		for (int a = 0; a < catTitle.length(); a++) {
			char charAt = catTitle.charAt(a);
			if (charAt == ' ' || charAt == '_') {
				continue;
			}
			bld.append(Character.toLowerCase(charAt));
		}
		return bld.toString();
	}

	@Override
	public int[] getCategoryMembers(int categoryId, boolean deep) {
		IntOpenHashSet hs = internalFillCSet(categoryId);
		if (deep) {
			int sz = 0;
			while (hs.size() != sz) {
				sz = hs.size();
				for (int a = 0; a < content.length; a++) {
					int i = content[a];
					if (i < 0) {
						int cc = -i;
						if (hs.contains(cc)) {
							for (int b = a + 1; b < content.length; b++) {
								i = content[b];
								if (i < 0) {
									break;
								}
								hs.add(i);
							}
						}
					}
				}

			}
		}
		return hs.toArray();
	}

	// private int remapTitle(String title, ITitleMapper titleMapper) {
	// int indexOf = title.indexOf("\\n");
	// if (title.equals("SOUTH KOREAN FIGHTER AIRCRAFT")){
	// System.out.println("A");
	// }
	// if (indexOf != -1) {
	// title = title.substring(indexOf + 2);
	// title = title.replace(' ', '_').toLowerCase();
	// title = Character.toUpperCase(title.charAt(0)) + title.substring(1);
	// return titleMapper.getId(title);
	// }
	// title = title.replace(' ', '_').toLowerCase();
	// title = Character.toUpperCase(title.charAt(0)) + title.substring(1);
	// return titleMapper.getId(title);
	// }

	@Override
	public int[] getParentCategories(int pateId, boolean all) {
		IntOpenHashSet hs = internalFillSet(pateId);
		if (all) {
			int[] array = hs.toArray();
			for (int a = 0; a < array.length; a++) {
				if (array[a] != pateId) {
					int[] parentCategories = getParentCategories(array[a], true);
					for (int c = 0; c < parentCategories.length; c++) {
						hs.add(parentCategories[a]);
					}
				}
			}
		}
		return hs.toArray();
	}

	protected IntOpenHashSet internalFillCSet(int pateId) {
		// System.out.println(db.getTitleMapper().getTitle(pateId));
		IntOpenHashSet hs = new IntOpenHashSet();
		for (int a = 0; a < content.length; a++) {
			int i = content[a];
			if (i < 0) {
				int cc = -i;
				if (cc == pateId) {
					for (int b = a + 1; b < content.length; b++) {
						i = content[b];
						if (i < 0) {
							// System.out.println(hs.size());
							return hs;
						} else {
							hs.add(i);
						}
					}
				}
			}
		}
		return hs;
	}

	public int[] getAllCategoriesWithChilren() {
		IntOpenHashSet hs = getAllCats();
		return hs.toArray();
	}

	protected IntOpenHashSet getAllCats() {
		IntOpenHashSet hs = new IntOpenHashSet();
		for (int a = 0; a < content.length; a++) {
			int i = content[a];
			if (i < 0) {
				int cc = -i;
				hs.add(cc);
			}
		}
		return hs;
	}

	public int[] getAllRoots() {
		IntOpenHashSet hs = getAllCats();
		for (int a = 0; a < content.length; a++) {
			int i = content[a];
			if (i > 0) {
				hs.remove(i);
			}
		}
		return hs.toArray();
	}

	protected IntOpenHashSet internalFillSet(int pateId) {
		int cc = -1;
		IntOpenHashSet hs = new IntOpenHashSet();
		for (int a = 0; a < content.length; a++) {
			int i = content[a];
			if (i < 0) {
				cc = -i;
			} else {
				if (pateId == i) {
					hs.add(cc);
				}
			}
		}
		return hs;
	}

	@Override
	public Set<String> getCategoryMembersAsTitles(int categoryId, boolean deep) {
		int[] categoryMembers = getCategoryMembers(categoryId, deep);
		return toTitles(categoryMembers);
	}

	@Override
	public Set<String> getParentCategoriesAsTitles(int pateId, boolean all) {
		int[] categoryMembers = getParentCategories(pateId, all);
		return toTitles(categoryMembers);
	}

	protected Set<String> toTitles(int[] categoryMembers) {
		HashSet<String> str = new HashSet<String>(categoryMembers.length);
		ITitleMapper titleMapper = db.getTitleMapper();
		for (int a = 0; a < categoryMembers.length; a++) {
			str.add(titleMapper.getTitle(categoryMembers[a]));
		}
		return str;
	}

	@Override
	public Map<Integer, IntOpenHashSet> getCategoryMembers(
			IntOpenHashSet categoryId, boolean deep) {
		HashMap<Integer, IntOpenHashSet> rs = new HashMap<Integer, IntOpenHashSet>();
		int lc = -1;
		boolean fill = false;
		IntOpenHashSet mm = null;
		for (int a = 0; a < content.length; a++) {
			int i = content[a];
			if (i < 0) {
				lc = -i;
				fill = categoryId.contains(lc);
				if (fill) {
					mm = rs.get(lc);
					if (mm == null) {
						mm = new IntOpenHashSet();
						rs.put(lc, mm);
					}
				}
			} else {
				if (fill) {
					mm.add(i);
				}
			}
		}
		return rs;
	}

	public HashMap<Integer, CatInf> buildInfoMap() {
		HashMap<Integer, CatInf> mm = new HashMap<Integer, CategoryRefMap.CatInf>();
		int lc = -1;
		boolean fill = false;
		CatInf cc = null;
		for (int a = 0; a < content.length; a++) {
			int i = content[a];
			if (i < 0) {
				lc = -i;
				CatInf catInf = mm.get(lc);
				if (catInf == null) {
					catInf = new CatInf(lc);
					catInf.id = lc;
					catInf.cats = new IntOpenHashSet();
					mm.put(lc, catInf);
				}
				cc = catInf;
			} else {
				cc.cats.add(i);
			}
		}
		return mm;
	}

	public Categories buildInfoMap2() {
		Categories t = new Categories();
		int lc = -1;
		for (int a = 0; a < content.length; a++) {
			int i = content[a];
			if (i < 0) {
				lc = -i;

			} else {
				if (lc != -1) {
					t.registerChild(lc, i);
				}
			}
		}
		return t;
	}

}
